package com.geekbang.coupon.template.controller;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.fastjson.JSON;
import com.geekbang.coupon.template.api.beans.CouponTemplateInfo;
import com.geekbang.coupon.template.api.beans.PagedCouponTemplateInfo;
import com.geekbang.coupon.template.api.beans.TemplateSearchParams;
import com.geekbang.coupon.template.service.intf.CouponTemplateServiceTCC;
import com.google.common.collect.Maps;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.util.Collection;
import java.util.Map;

@Slf4j
@RestController
@RequestMapping("/template")
public class CouponTemplateController {

	 @Autowired
    private CouponTemplateServiceTCC couponTemplateService;

    // 创建优惠券
    @PostMapping("/addTemplate")
    public CouponTemplateInfo addTemplate(@Valid @RequestBody CouponTemplateInfo request) {
        log.info("Create coupon template: data={}", request);
        return couponTemplateService.createTemplate(request);
    }

    @PostMapping("/cloneTemplate")
    public CouponTemplateInfo cloneTemplate(@RequestParam("id") Long templateId) {
        log.info("Clone coupon template: data={}", templateId);
        return couponTemplateService.cloneTemplate(templateId);
    }

    // 读取优惠券
    @GetMapping("/getTemplate")
	@SentinelResource(value = "getTemplate")
    public CouponTemplateInfo getTemplate(@RequestParam("id") Long id){
        log.info("Load template, id={}", id);
        return couponTemplateService.loadTemplateInfo(id);
    }

    // 批量获取
    @GetMapping("/getBatch")
	// 你也可以通过defaultFallback属性做一个全局限流、降级的处理逻辑
    // 如果你不想将降级方法写在当前类里，可以通过blockHandlerClass和fallbackClass指定"降级类"
	// 对于降级方法：请求被sentinel拦截时产生BlockException异常，此异常触发blockHandler，
	// 对其他异常无效，而fallback可以应对其他异常
    @SentinelResource(value = "getTemplateInBatch",
            fallback = "getTemplateInBatch_fallback",
            blockHandler = "getTemplateInBatch_block")
    public Map<Long, CouponTemplateInfo> getTemplateInBatch(@RequestParam("ids") Collection<Long> ids) {
        log.info("getTemplateInBatch: {}", JSON.toJSONString(ids));

		// 可以测试异常比例、异常数熔断
		/*
        if (ids.size() == 2) {
            throw new RuntimeException("!!! throws an exception when id num=2");
        }
		*/
        // 可以测试慢调用熔断，注意不要触发openfeign配置的超时异常
		/*
		try {
			Thread.sleep(500 * ids.size());
		} catch (Exception e) {}
		*/

        return couponTemplateService.getTemplateInfoMap(ids);
    }

	// 响应除BlockException外的RuntimeExecption，返回空数据
    public Map<Long, CouponTemplateInfo> getTemplateInBatch_fallback(Collection<Long> ids) {
        log.info("!!! getTemplateInBatch_fallback");
        return Maps.newHashMap();
    }

    // 响应BlockException，返回空数据
    public Map<Long, CouponTemplateInfo> getTemplateInBatch_block(
            Collection<Long> ids, BlockException e) {
        log.info("!!! getTemplateInBatch_block");
        return Maps.newHashMap();
    }

    // 搜索模板
    @PostMapping("/search")
    public PagedCouponTemplateInfo search(@Valid @RequestBody TemplateSearchParams request) {
        log.info("search templates, payload={}", request);
        return couponTemplateService.search(request);
    }

    // 优惠券无效化
    @DeleteMapping("/deleteTemplate")
    public void deleteTemplate(@RequestParam("id") Long id){
        log.info("delete template, id={}", id);
        couponTemplateService.deleteTemplateTCC(id);
    }

	// 优惠券无效化
	@DeleteMapping("/deleteTemplateTCC")
	public void deleteTemplateTCC(@RequestParam("id") Long id){
		log.info("delete template, id={}", id);
		// 为什么TCC接口实现用的不是deleteTemplateTCC
		couponTemplateService.deleteTemplate(id);
	}

}
